package com.lc.activiti.sys.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.DES;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lc.activiti.config.ConstantsPile;
import com.lc.activiti.config.Result;
import com.lc.activiti.sys.entity.*;
import com.lc.activiti.sys.service.*;
import com.lc.activiti.utils.SecurityUtil;
import com.lc.activiti.sys.dao.SysUserDao;
import com.lc.activiti.utils.JwtUtil;
import com.lc.activiti.utils.RSAUtils;
import com.lc.activiti.utils.WebSocketServer;
import com.lc.activiti.utils.redis.RedisUtil;
import com.lc.activiti.utils.sms.SmsEntity;
import com.lc.activiti.utils.sms.SmsUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * (SysUser)表服务实现类
 *
 * @author makejava
 * @since 2021-05-20 10:52:45
 */
@Service("sysUserService")
public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUser> implements SysUserService {

    @Resource
    private SysCoverService sysCoverService;
    @Resource
    private SysRoleService roleService;
    @Resource
    private SysUserRoleService userRoleService;
    @Resource
    private SysFileService fileService;

    @Override
    public SysUser saveUserInfo(SysUser sysUser) {
        String rules = null;
        DES des = null;
        if (ObjectUtil.isNull(sysUser.getId())||ObjectUtil.isNotEmpty(sysUser.getPassword())) {
            //随机生成密钥
            byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue()).getEncoded();
            //构建des
            des = SecureUtil.des(key);
            //将字节转化为16进制字符串
            rules = HexUtil.encodeHexStr(key);
        }
        if (ObjectUtil.isNotEmpty(sysUser.getAvatar())){
            SysFile sysFile = fileService.getById(sysUser.getAvatar());
            fileService.update(Wrappers.lambdaUpdate(SysFile.class).ne(SysFile::getId,sysFile.getId()).set(SysFile::getDelFlag, 0));
            sysFile.setRelationId(sysUser.getId());
            sysFile.setScene("avatar");
            sysFile.insertOrUpdate();
        }
        boolean result = sysUser.insertOrUpdate();
        if (result && ObjectUtil.isNotNull(rules)) {
            sysCoverService.remove(Wrappers.lambdaQuery(SysCover.class).eq(SysCover::getRelationId,sysUser.getId()));
            SysCover sysCover = new SysCover();
            sysCover.setRelationId(sysUser.getId());
            sysCover.setDesKeyHex(rules);
            sysCover.setTableName("sys_user");
            sysCover.setCoverStr(des.encryptHex(sysUser.getPassword()));
            //保存加密内容
            sysCover.insertOrUpdate();
        }
        this.setUserMap();
        return sysUser;
    }

    /**
     * 往redis中塞入用户id-名称值对
     *
     * @author 骆超
     * @date 2021/6/18
     */
    @Override
    public void setUserMap() {
        List<SysUser> list = list();
        Map<Long, String> userMap = list.stream().collect(Collectors.toMap(SysUser::getId, SysUser::getName));
        //将userMap存入redis中
        RedisUtil.set(ConstantsPile.USER_MAP, userMap);
    }


    @Override
    public Result loginAction(SysUser sysUser) {
        SysUser queryUser = baseMapper.selectOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getUserName, sysUser.getUserName()).or().eq(SysUser::getPhoneNum, sysUser.getUserName()));
        if (ObjectUtil.isEmpty(queryUser)) {
            return Result.failed("账户不存在！");
        }
        try {
            //获取存储在redis中的私钥
            String privateKey = RedisUtil.get(ConstantsPile.RSA_PRIVATE_KEY).toString();
            //rsa解密数据，获得原始密码
            String realPwd = RSAUtils.decrypt(sysUser.getPassword(), RSAUtils.getPrivateKey(privateKey));
            //找到数据库存入的des加密数据
            SysCover sysCover = sysCoverService.getOne(Wrappers.lambdaQuery(SysCover.class).eq(SysCover::getRelationId, queryUser.getId()).eq(SysCover::getDelFlag, 1));
            //初始化des
            DES des = SecureUtil.des(HexUtil.decodeHex(sysCover.getDesKeyHex()));
            //des解密，获取加密内容
            String decodeStr = des.decryptStr(sysCover.getCoverStr());
            //匹配加密数据是否一致
            if (realPwd.equals(decodeStr)) {
                //将用户信息封装进token中
                queryUser.setToken(JwtUtil.sign(queryUser));
                return Result.success(queryUser).setMsg("登录成功！");
            } else {
                return Result.failed("登录失败！");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Result.failed("登录异常！");
        }
    }

    @Override
    public Page<SysUser> getUserList(SysUser sysUser) {
        Page<SysUser> page = page(sysUser.getPage(), Wrappers.lambdaQuery(SysUser.class).like(ObjectUtil.isNotEmpty(sysUser.getName()), SysUser::getName, sysUser.getName()).eq(ObjectUtil.isNotEmpty(sysUser.getDeptId()), SysUser::getDeptId, sysUser.getDeptId()).or().isNull(ObjectUtil.isNotEmpty(sysUser.getDeptId()) && !sysUser.getIsOnly(), SysUser::getDeptId).orderByDesc(SysUser::getCreateDate));
        List<SysRole> roleList = roleService.list();
        List<SysUserRole> userRoles = userRoleService.list(Wrappers.lambdaQuery(SysUserRole.class).ne(SysUserRole::getUserId, "").ne(SysUserRole::getRoleId, ""));
        page.getRecords().forEach(user ->
                user.setRoleList(roleList.stream().filter(role -> userRoles.stream().filter(userRole -> userRole.getUserId().equals(user.getId())).map(SysUserRole::getRoleId).collect(Collectors.toList()).contains(role.getId())).collect(Collectors.toList()))
        );
        return page;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result saveDeptUsers(SysUser sysUser) {
        update(Wrappers.lambdaUpdate(SysUser.class).eq(SysUser::getDeptId, sysUser.getDeptId()).set(SysUser::getDeptId, null));
        return Result.success(updateBatchById(sysUser.getUserList()));
    }

    @Override
    public Result logOutAction() {
        WebSocketServer.onClose(String.valueOf(JwtUtil.getUser().getId()));
        return Result.success("退出登录成功！");
    }

    @Override
    public Result sendRegisterCode(SysUser sysUser) {
        // 找出该手机号是否已经使用过了
        int count = count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhoneNum, sysUser.getPhoneNum()));
        if (count > 0) {
            return Result.failed("此手机号已经被注册，请使用其他号码！");
        }
        return sendMsg("1033472", sysUser.getPhoneNum());
    }

    @Override
    public Result registerAccount(SysUser sysUser) {
        String code = getRedisMsgCode(sysUser.getPhoneNum());
        if (!"-1".equals(code)){
            if (code.equals(sysUser.getMsgCode())) {
                sysUser.setName("用户" + sysUser.getPhoneNum());
                this.saveUserInfo(sysUser);
                //验证码使用过之后，redis中需要销毁
                RedisUtil.clearOfKey(sysUser.getPhoneNum());
                return Result.success(sysUser);
            } else {
                return Result.failed("验证码不正确！");
            }
        }else{
            return Result.failed("验证码不存在或已过期！");
        }
    }


    /**
     * 发送找回密码的短信
     * @author 骆超
     * @date 2021/7/14
     * @param sysUser 参数说明
     * @return com.lc.activiti.config.Result
     */
    @Override
    public Result sendBackCode(SysUser sysUser) {
        SysUser user = getOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getPhoneNum, sysUser.getPhoneNum()));
        if (ObjectUtil.isEmpty(user)) {
            return Result.failed("该手机号还未注册过账号！");
        } else {
            return sendMsg("1035566", sysUser.getPhoneNum());
        }
    }


    /**
     * 找回密码
     * @author 骆超
     * @date 2021/7/14
     * @param sysUser 参数说明
     * @return com.lc.activiti.config.Result
     */
    @Override
    public Result backPassword(SysUser sysUser) {
        String code = getRedisMsgCode(sysUser.getPhoneNum());
        if (!"-1".equals(code)){
            if (code.equals(sysUser.getMsgCode())) {
                sysUser = getOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getPhoneNum, sysUser.getPhoneNum()));
                String pwd = ObjectId.next().substring(0,6);
                sysUser.setPassword(pwd);
                this.saveUserInfo(sysUser);
                //验证码使用过之后，redis中需要销毁
                RedisUtil.clearOfKey(sysUser.getPhoneNum());
                SmsUtil.sendPhoneTextMsg(
                        new SmsEntity()
                                .setTemplateId("1035727")
                                .setSign("心情随记")
                                .setPhoneNumbers(new String[]{"+86" + sysUser.getPhoneNum()})
                                .setParams(new String[]{pwd})
                );
                return Result.success(sysUser);
            } else {
                return Result.failed("验证码不正确！");
            }
        }else{
            return Result.failed("验证码不存在或已过期！");
        }
    }

    /**
     * 获取redis中的验证码
     * @author 骆超
     * @date 2021/7/14
     * @param phoneNum 参数说明
     * @return java.lang.Integer
     */
    private String getRedisMsgCode(String phoneNum) {
        Object code = RedisUtil.get(phoneNum);
        if (ObjectUtil.isNotEmpty(code)) {
            return (String) code;
        } else {
            return "-1";
        }
    }

    /**
     * 发送短信
     * @author 骆超
     * @date 2021/7/14
     * @param templateId 参数说明
     * @param phoneNum 参数说明
     * @return com.lc.activiti.config.Result
     */
    private Result sendMsg(String templateId, String phoneNum) {
        // 自定义纯数字的验证码（随机4位数字，可重复）
        RandomGenerator randomGenerator = new RandomGenerator("0123456789", 6);
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
        lineCaptcha.setGenerator(randomGenerator);
        RedisUtil.set(phoneNum, lineCaptcha.getCode(), 5);
        Boolean result = SmsUtil.sendPhoneTextMsg(
                new SmsEntity()
                        .setTemplateId(templateId)
                        .setSign("心情随记")
                        .setPhoneNumbers(new String[]{"+86" + phoneNum})
                        .setParams(new String[]{lineCaptcha.getCode(), "5"})
        );
        if (result) {
            return Result.success("验证码已发送！");
        } else {
            return Result.failed("验证短信发送失败！");
        }
    }


    /**
     * 发送手机号换绑短信
     * @author 骆超
     * @date 2021/7/16
     * @param sysUser 参数说明
     * @return com.lc.activiti.config.Result
     */
    @Override
    public Result sendReplaceMsg(SysUser sysUser) {
        //判断新绑定的手机号是否关联过账号
        int count = count(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getPhoneNum, sysUser.getPhoneNum()));
        if (count>0){
            return Result.failed("此手机号已绑定相关账号，请更换其他手机号！");
        }else{
            return sendMsg("1038505", sysUser.getPhoneNum());
        }
    }

    /**
     * 更换手机绑定
     * @author 骆超
     * @date 2021/7/16
     * @param sysUser 参数说明
     * @return com.lc.activiti.config.Result
     */
    @Override
    public Result replacePhoneNum(SysUser sysUser) {
        String code = getRedisMsgCode(sysUser.getPhoneNum());
        if (!"-1".equals(code)){
            if (code.equals(sysUser.getMsgCode())) {
                updateById(sysUser);
                //验证码使用过之后，redis中需要销毁
                RedisUtil.clearOfKey(sysUser.getPhoneNum());
                return Result.success(sysUser);
            } else {
                return Result.failed("验证码不正确！");
            }
        }else{
            return Result.failed("验证码不存在或已过期！");
        }
    }
}
